package com.polly.esphwevent.services;

import cn.hutool.core.date.DateUtil;
import com.polly.esphwevent.common.constants.AuthConstants;
import com.polly.esphwevent.common.exceptions.AuthExceptionEnum;
import com.polly.esphwevent.common.exceptions.ServiceException;
import com.polly.esphwevent.common.jwtutils.JwtTokenUtil;
import com.polly.esphwevent.domain.AuthToken;
import com.polly.esphwevent.domain.UserInfo;
import com.polly.esphwevent.repository.SetCacheDao;
import com.polly.esphwevent.repository.StringCacheDao;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.servlet.http.HttpServletRequest;
import java.util.*;
import java.util.concurrent.TimeUnit;


/**
 * @author liqin@nd.com.cn
 * @version V1.0
 * @title: CommentService
 * @description: TODO(用一句话描述该文件做什么)
 * @date: 2019/3/28 10:58
 */
@Service
public class CommentService {

    @Autowired
    private StringCacheDao<String, UserInfo> tokenCacheDao;
    @Autowired
    private StringCacheDao<String, String> refreshTokenCacheDao;
    @Autowired
    private SetCacheDao<String,String> tokenSetCacheDao;
    @Autowired
    private SetCacheDao<String,String> refreshTokenSetCacheDao;
    @Autowired
    JwtTokenUtil jwtTokenUtil;

    public AuthToken createComment(Long userId){
        AuthToken token = new AuthToken();
        UserInfo userInfo = new UserInfo();
        userInfo.setUserId(userId);
        Date expiredDate = DateUtil.offsetDay(new Date(),7);
        Date refreshExpiredDate = DateUtil.offsetDay(expiredDate,7);
        Map<String, Object> claims= new HashMap<>();
        claims.put("scopes","basic");
        token.setServerTime(System.currentTimeMillis());
        token.setAccessToken(jwtTokenUtil.generateToken(String.valueOf(userId),expiredDate,claims));
        token.setRefreshToken(jwtTokenUtil.generateToken(String.valueOf(userId),refreshExpiredDate,null));
        token.setScope("basic");//可扩展
        token.setTokenType("bearer");
        //cache  userId
        tokenCacheDao.set("accessToken:"+token.getAccessToken(),userInfo,expiredDate.getTime(), TimeUnit.MILLISECONDS);
        refreshTokenCacheDao.set("refreshToken:"+token.getRefreshToken(),token.getAccessToken(),refreshExpiredDate.getTime(),TimeUnit.MILLISECONDS);
        //set cache
        tokenSetCacheDao.add("accessToken:"+userId,token.getAccessToken());
        refreshTokenSetCacheDao.add("refreshToken:"+userId,token.getRefreshToken());
        return token;
    }

    public AuthToken refreshComment(String refreshToken){

        //校验过期
        if(jwtTokenUtil.isTokenExpired(refreshToken)) {
            throw new ServiceException(AuthExceptionEnum.TOKEN_EXPIRED);
        }
        //校验合法性
        String accessToken = refreshTokenCacheDao.get(refreshToken);
        if(null == accessToken) {
            throw new ServiceException(AuthExceptionEnum.TOKEN_INVALID);
        }
        tokenCacheDao.delete(accessToken);
        refreshTokenCacheDao.delete(refreshToken);
        //删除
        Long userId = Long.valueOf(jwtTokenUtil.getClaimFromToken(refreshToken).getSubject());
        tokenSetCacheDao.remove("accessToken:"+userId,refreshToken);
        refreshTokenSetCacheDao.remove("refreshToken:"+userId,accessToken);

        return createComment(userId);
    }

    public void deleteComment(Long userId){
        //遍历所有
        Set<String> tokenList = tokenSetCacheDao.members("accessToken:"+userId);
        Iterator<String> tokenIterator= tokenList.iterator();
        while (tokenIterator.hasNext()){
            tokenCacheDao.delete(tokenIterator.next());
        }
        tokenSetCacheDao.delete("accessToken:"+userId);

        Set<String> refreshTokenList = refreshTokenSetCacheDao.members("refreshToken:"+userId);
        Iterator<String> refreshIterator= refreshTokenList.iterator();
        while (refreshIterator.hasNext()){
            refreshTokenSetCacheDao.delete(refreshIterator.next());
        }
        refreshTokenSetCacheDao.delete("refreshToken:"+userId);


    }

    public boolean doValidate(HttpServletRequest request) {
        String tokenFromRequest = this.getTokenFromRequest(request);
        return this.validateToken(tokenFromRequest, request);
    }

    private String getTokenFromRequest(HttpServletRequest request) {
        //获取token
        String authTokenStr = request.getHeader(AuthConstants.AUTH_HEADER);
        if (StringUtils.isEmpty(authTokenStr)) {
            authTokenStr = request.getParameter("accessToken");
            if (StringUtils.isEmpty(authTokenStr)) {
                throw new ServiceException(AuthExceptionEnum.TOKEN_EMPTY);
            }
        } else {
            authTokenStr = authTokenStr.substring("Bearer ".length());
        }

        return authTokenStr;
    }

    protected boolean validateToken(String token, HttpServletRequest request){
        try {
            boolean flag = jwtTokenUtil.isTokenExpired(token);
            if (flag) {
                throw new ServiceException(AuthExceptionEnum.TOKEN_ERROR);
            } else {
                return true;
            }
        } catch (Exception e) {
            throw new ServiceException(AuthExceptionEnum.TOKEN_ERROR);
        }
    }

}
